/* 进程扇 */
#include "snetwork/WorkerProcess.h"
#include "processlog.h"
#include "getoption.h"
#include "channel.h"
#include "snetwork/MasterProcess.h"
#include "snetwork/Context.h"
#include "SignalProcess.h"

int CMasterProcess::ChildRealLive()
{
    int child_live = 0;
    for (int i = 0; i < http_last_process; i++) {
        if (!http_processes[i].exited) {
            child_live++;
        }
    }
    
    return child_live;
}


int CMasterProcess::CreateProcess(nlu_cycle_t *cycle)
{
    int z, s;
    
    // init process
    for (s = 0; s < http_last_process; s++) {
        if (http_processes[s].pid == -1) {
            break;
        }
    }
    
    z = socketpair(AF_LOCAL,SOCK_STREAM,0,http_processes[s].channel);
    
    http_channel_id = http_processes[s].channel[1];
    http_process_slot = s;

    pid_t pid = fork();   
     
    switch (pid) {
        case -1: return -1;
        case 0: Sock::CWorkerProcess::instance()->WorkerProcessCycle(cycle); break;
        default: break;
    }
    
    http_processes[s].pid = pid;   
    http_processes[s].exited = 0;

    http_processes[s].data = NULL;
    http_processes[s].name = NULL;
    http_processes[s].exiting = 0;
    
    if (s == http_last_process) {
        http_last_process++;
    }
      
    return 0;
}

int CMasterProcess::StartWorkerProcesses(nlu_cycle_t *cycle, int proc_num)
{
    http_channel_t  ch;
    
    for (int i=0; i<proc_num; i++) {
    
        this->CreateProcess(cycle);
        
        ch.pid = http_processes[http_process_slot].pid;
        ch.slot = http_process_slot;
        ch.fd = http_processes[http_process_slot].channel[0];
        
        for (int i = 0; i < http_last_process; i++) {

            if (i == http_process_slot
                || http_processes[i].pid == -1
                || http_processes[i].channel[0] == -1)
            {
                continue;
            }
            
            httpd_write_channel(http_processes[i].channel[0], 
                        &ch, sizeof(http_channel_t));
        }
    }                        
    return 0;
}

int CMasterProcess::SignalWorkerProcesses()
{
    for (int i = 0; i < http_last_process; i++) {
        llog("kill signal child process %d ?!", http_processes[i].pid);
        kill(http_processes[i].pid, SIGTERM);    
    }
    
    return 0;
}

void CMasterProcess::InitCycle(nlu_cycle_t *cycle)
{
    CMyPool my;
    nlu_pool_t *pool;
    
    pool = my.createPool(16383);
    
    cycle = my.nluPcalloc(pool, sizeof(nlu_cycle_t));
    
    if (cycle == NULL) {
        my.destoryPool(pool);
        return;
    }
    
    cycle->connection_n = 1;
    cycle->pool = pool;
}

void CMasterProcess::CloseCycle(nlu_cycle_t *cycle)
{
    CMyPool my;
    
    my.destoryPool(cycle->pool);
}

int CMasterProcess::MasterProcessCycle()
{
    int                 status;
    int                 live = 1;
    http_channel_t      ch; 
 
    nlu_cycle_t         *cycle;   
    
    this->InitCycle(cycle);
    
    // start n process?
    int num_process = 1;
    this->StartWorkerProcesses(cycle, num_process);

    sigset_t set;      
    sigemptyset(&set);         
    
    for ( ; ; ) {      
                  
        if (http_reap) {
            live = this->ChildRealLive();
            http_reap = 0;
        }
        else {
            sigsuspend(&set); 
        }
        
        if (!live) {
            llog("main process exit");
            exit(0);
        }
    
        if ( http_quit || http_terminate ) {
            this->SignalWorkerProcesses();
            
            http_quit = 0;
            http_terminate = 0;
        }
        
        if ( http_reconfigure || http_reopen ) {
            this->SignalWorkerProcesses();                        
            this->StartWorkerProcesses(num_process);            
            
            http_reconfigure = 0;
        }
        
        sleep(1);
    }    
    
    this->CloseCycle(cycle);
    
    return 0;
}
